unit MySQLFrame;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, ActnList,
  JwaWinSvc, Dialogs;

type

  { TMySQLModule }

  TMySQLModule = class(TFrame)
    acRestart: TAction;
    acStart: TAction;
    acStop: TAction;
    acChangePassword: TAction;
    acOpenClient: TAction;
    acUninstall: TAction;
    btnMySQLConf: TButton;
    btnMySQLConf1: TButton;
    btnMySQLChangePassword: TButton;
    btnMySQLConf2: TButton;
    btnRecoveryDist: TButton;
    btnRecoveryDist1: TButton;
    btnRecoveryDist2: TButton;
    btnRecoveryDist3: TButton;
    btnRecoveryDist4: TButton;
    GroupBox2: TGroupBox;
    GroupBox3: TGroupBox;
    MySQLAction: TActionList;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    cbMySQLVersion: TComboBox;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    lbMySQLStatus: TLabel;
    procedure acChangePasswordExecute(Sender: TObject);
    procedure acChangePasswordUpdate(Sender: TObject);
    procedure acOpenClientExecute(Sender: TObject);
    procedure acOpenClientUpdate(Sender: TObject);
    procedure acRestartExecute(Sender: TObject);
    procedure acRestartUpdate(Sender: TObject);
    procedure acStartExecute(Sender: TObject);
    procedure acStartUpdate(Sender: TObject);
    procedure acStopExecute(Sender: TObject);
    procedure acStopUpdate(Sender: TObject);
    procedure acUninstallExecute(Sender: TObject);
    procedure acUninstallUpdate(Sender: TObject);
    procedure btnMySQLConfClick(Sender: TObject);
    procedure btnRecoveryDistClick(Sender: TObject);
    procedure cbMySQLVersionChange(Sender: TObject);
  private
    { private declarations }
    ServiceName: String;
    FServiceStatus: Boolean;
    FServiceInstalledStatus: Boolean;
    function GetServiceStatus: Boolean;
    function GetServiceInstalledStatus: Boolean;
    procedure SetServiceStatus(Status: Boolean);
    procedure SetServiceInstalledStatus(Status: Boolean);
  public
    { public declarations }
    constructor Create(AOwner: TComponent); override;
    procedure ServiceInstall;
    procedure ServiceStart;
    procedure ServiceStop;
    procedure ServiceRestart;
    procedure ServiceUninstall;
  published
    property ServiceStatus: Boolean read FServiceStatus write SetServiceStatus;
    property ServiceInstalledStatus: Boolean read FServiceInstalledStatus write SetServiceInstalledStatus;
  end;

implementation
uses functions, MainForm;

{$R *.lfm}

{ TMySQLModule }

procedure TMySQLModule.acStartExecute(Sender: TObject);
begin
  ServiceStart;
  Log('启动MySQL');

  if not ServiceInstalledStatus then
  begin
    MessageDlg('错误','服务安装失败，服务无法启动！', mtError, [mbOK], 0)
  end
  else
  begin
    if not ServiceStatus then
    begin
      MessageDlg('错误','服务启动失败，可能是配置文件错误！',mtError,[mbOK],0);
    end;
  end;
end;

procedure TMySQLModule.acStartUpdate(Sender: TObject);
begin
  acStart.Enabled := not ServiceStatus;
end;

procedure TMySQLModule.acRestartExecute(Sender: TObject);
begin
  ServiceRestart;
  Log('重启MySQL');
end;

procedure TMySQLModule.acChangePasswordExecute(Sender: TObject);
var
  OldPassword, NewPassword, NewPassword2, CMD, FileName: String;
begin
  OldPassword := Trim(PasswordBox('原密码','请输入原密码，如果是初次使用，请留空'));
  NewPassword := Trim(PasswordBox('新密码','请输入新的root密码'));
  NewPassword2 := Trim(PasswordBox('新密码','请再次输入新的root密码'));
  if NewPassword <> NewPassword2 then
  begin
    MessageDlg('错误','两次新密码输入不相同！',mtError,[mbOK],0);
    exit;
  end;
  FileName := ExpandFileName(ExtractFilePath(ParamStr(0))+'..\program\mysql\'+MySQLStatus.version+'\bin\mysqladmin.exe');
  CMD := FileName + ' -u root';
  if OldPassword <> '' then CMD := CMD + ' --password=' + OldPassword;
  CMD := CMD + ' password ' + NewPassword;
  RunCMD(CMD);
  MessageDlg('提示','修改完成，请点击"打开mysql终端"检查密码修改是否成功！',mtInformation,[mbOK],0);
  Log('修改MySQL root密码');
end;

procedure TMySQLModule.acChangePasswordUpdate(Sender: TObject);
begin
  acChangePassword.Enabled := ServiceStatus;
end;

procedure TMySQLModule.acOpenClientExecute(Sender: TObject);
var
  CMD, Password: String;
begin
  Password := Trim(PasswordBox('密码','请输入root密码，如果没有设置请留空'));
  CMD := 'cmd.exe /c ' + ExpandFileName(ExtractFilePath(ParamStr(0))+'..\program\mysql\'+MySQLStatus.version+'\bin\mysql.exe') + ' -u root';
  if Password <> '' then CMD := CMD + ' --password='+Password;

  RunCMD(CMD);
end;

procedure TMySQLModule.acOpenClientUpdate(Sender: TObject);
begin
  acOpenClient.Enabled := ServiceStatus;
end;

procedure TMySQLModule.acRestartUpdate(Sender: TObject);
begin
  acRestart.Enabled := ServiceStatus;
end;

procedure TMySQLModule.acStopExecute(Sender: TObject);
begin
  ServiceStop;
  Log('停止MySQL');
end;

procedure TMySQLModule.acStopUpdate(Sender: TObject);
begin
  acStop.Enabled := ServiceStatus;
end;

procedure TMySQLModule.acUninstallExecute(Sender: TObject);
begin
  ServiceUninstall;
  Log('卸载MySQL');
end;

procedure TMySQLModule.acUninstallUpdate(Sender: TObject);
begin
  acUninstall.Enabled := not ServiceStatus and ServiceInstalledStatus;
end;

procedure TMySQLModule.btnMySQLConfClick(Sender: TObject);
var
  CMD, Password: String;
begin
  case (Sender as TButton).Tag of
    0: CMD := 'notepad.exe ..\program\mysql\'+MySQLStatus.version+'\my.ini';
    1: CMD := 'cmd.exe /k cd /d ' + ExpandFileName(ExtractFilePath(ParamStr(0))+'..\program\mysql\'+MySQLStatus.version+'\bin');
    2: begin
      Password := Trim(PasswordBox('密码','请输入root密码，如果没有设置请留空'));
      CMD := 'cmd.exe /c ' + ExpandFileName(ExtractFilePath(ParamStr(0))+'..\program\mysql\'+MySQLStatus.version+'\bin\mysql.exe') + ' -u root';
      if Password <> '' then CMD := CMD + ' --password='+Password;
    end;
  end;
  RunCMD(CMD);
end;

procedure TMySQLModule.btnRecoveryDistClick(Sender: TObject);
var
  FileName, FilePath: String;
begin
  if MessageDlg('提示','您确实要切换配置文件么？如果您修改过my.ini，那么所有修改将全部删除。',mtInformation,[mbYes, mbNo], 0) = mrYes then
  begin
    if ServiceStatus then
      ServiceStop;
    FilePath := ExpandFileName(ExtractFilePath(ParamStr(0))+'..\program\mysql\'+MySQLStatus.version);
    case (Sender as TButton).Tag of
      0: FileName := 'my-small.ini';
      1: FileName := 'my-medium.ini';
      2: FileName := 'my-large.ini';
      3: FileName := 'my-huge.ini';
      4: FileName := 'my-innodb-heavy-4G.ini';
    end;
    CopyFile(FilePath + '\' + FileName, FilePath + '\my.ini', [cffOverwriteFile]);
    Log('切换MySQL配置为：'+FileName);
    ServiceStart;
  end;
end;

procedure TMySQLModule.cbMySQLVersionChange(Sender: TObject);
begin
  if not LoadingDataStatus then
  begin
    LoadingDataStatus := True;
    Log('MySQL版本从'+MySQLStatus.version+'切换为：'+cbMySQLVersion.Text);
    ServiceStop;
    ServiceUninstall;
    MySQLStatus.version := cbMySQLVersion.Text;
    ChangeProgramVersion(2);
    ServiceStart;
    LoadingDataStatus := False;
  end;
end;

function TMySQLModule.GetServiceStatus: Boolean;
var
  schm, schs: SC_Handle;
  ss: TServiceStatus;
  dwStat: DWord;
begin
  dwstat := 0;
  schm := OpenSCManager(PChar(''), Nil, SC_MANAGER_CONNECT);
  { Connect to Machine }
  if schm > 0 then
  begin
    schs := OpenService(schm, PChar(ServiceName), SERVICE_QUERY_STATUS);
    { Open Service }
    if schs > 0 then
    begin
      if(QueryServiceStatus(schs, ss))then
      begin
        dwStat := ss.dwCurrentState;
      end;
      CloseServiceHandle(schs);
    end;
    CloseServiceHandle(schm);
  end;
  Result := dwstat = SERVICE_RUNNING;
end;

function TMySQLModule.GetServiceInstalledStatus: Boolean;
var
  schm, schs: SC_Handle;
  ss: TServiceStatus;
  dwStat: DWord;
begin
  Result := False;
  dwstat := 0;
  schm := OpenSCManager(PChar(''), Nil, SC_MANAGER_CONNECT);
  { Connect to Machine }
  if schm > 0 then
  begin
    schs := OpenService(schm, PChar(ServiceName), SERVICE_QUERY_STATUS);
    { Open Service }
    if schs > 0 then
      begin
        if(QueryServiceStatus(schs, ss))then
        begin
          dwStat := ss.dwCurrentState;
        end;
        CloseServiceHandle(schs);
      end;
    CloseServiceHandle(schm);
  end;
  Result := dwstat <> 0;
end;

procedure TMySQLModule.SetServiceStatus(Status: Boolean);
begin
  FServiceStatus := Status;
  if Status then
  begin
    lbMySQLStatus.Caption := '状态：运行';
    MySQLStatus.status := 1;
  end
  else
  begin
    lbMySQLStatus.Caption := '状态：停止';
    MySQLStatus.status := 0;
  end;
  Main.updateStatus;
end;

procedure TMySQLModule.SetServiceInstalledStatus(Status: Boolean);
begin
  FServiceInstalledStatus := Status;
end;

constructor TMySQLModule.Create(AOwner: TComponent);
var
  DirPath: String;
  TSL: TStringList;
  i: Integer;
begin
  inherited Create(AOwner);

  ServiceName := 'Away_MySQL';
  ServiceInstalledStatus := GetServiceInstalledStatus;
  ServiceStatus := GetServiceStatus;


  // 检测不存在的版本，并删除
  TSL := TStringList.Create;
  DirPath := ExpandFileName(ExtractFilePath(ParamStr(0))+'..\program\mysql') + '\';
  for i := 0 to cbMySQLVersion.Items.Count - 1 do
  begin
    if DirectoryExists(DirPath + cbMySQLVersion.Items[i]) then
      TSL.Add(cbMySQLVersion.Items[i]);
  end;
  cbMySQLVersion.Items.Text:=TSL.Text;
  TSL.Free;

  cbMySQLVersion.ItemIndex := cbMySQLVersion.Items.IndexOf(MySQLStatus.Version);

  // 当前版本不存在
  if cbMySQLVersion.ItemIndex = -1 then
  begin
    if cbMySQLVersion.Items.Count > 0 then
    begin
      cbMySQLVersion.ItemIndex := 0;
      MySQLStatus.version := cbMySQLVersion.Items[0];
      ChangeProgramVersion(3);  // 写入配置文件
    end;
  end;
end;

procedure TMySQLModule.ServiceInstall;
var
  FileName, FilePath, CMD: String;
begin
  // Service Exe File
  FilePath := ExpandFileName(ExtractFilePath(ParamStr(0))+'..\program\mysql\'+MySQLStatus.version);
  FileName := FilePath+'\bin\mysqld.exe';

  if not ServiceInstalledStatus then
  begin
    CMD := FileName + ' --install ' + ServiceName + ' --defaults-file='+FilePath+'\my.ini';
    RunCMD(CMD);
    ServiceInstalledStatus := GetServiceInstalledStatus;
  end;
end;

procedure TMySQLModule.ServiceStart;
var
  CMD: String;
begin
  if not ServiceInstalledStatus then
    ServiceInstall;

  if ServiceInstalledStatus then
  begin
    CMD := 'net start Away_MySQL';
    RunCMD(CMD);
    ServiceStatus := GetServiceStatus;
  end;
end;

procedure TMySQLModule.ServiceStop;
var
  CMD: String;
begin
  CMD := 'net stop Away_MySQL';
  RunCMD(CMD);
  ServiceStatus := GetServiceStatus;
end;

procedure TMySQLModule.ServiceRestart;
begin
  ServiceStop;
  ServiceStart;
end;

procedure TMySQLModule.ServiceUninstall;
var
  FileName, FilePath, CMD: String;
begin
  // Service Exe File
  FilePath := ExpandFileName(ExtractFilePath(ParamStr(0))+'..\program\mysql\'+MySQLStatus.version);
  FileName := FilePath+'\bin\mysqld.exe';

  if ServiceInstalledStatus then
  begin
    CMD := FileName + ' --remove ' + ServiceName;
    RunCMD(CMD);
    ServiceInstalledStatus := GetServiceInstalledStatus;
  end;
end;

end.

